﻿using LiteBlog.Repositories.Common;
using LiteBlog.Repositories.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace LiteBlog.Repositories.Framework
{
    public abstract class StandardRepository<T> : IStandardRepository<T>, IRepository
    {
        public StandardRepository(IDataContext context, IXmlHelper xmlHelper)
        {
            _context = context;
            _xmlHelper = xmlHelper;
        }

        public IEnumerable<T> Get()
        {
            var list = new List<T>();
            var root = _xmlHelper.Load(_path);
            foreach (XElement elem in root.Elements(_elementName))
            {
                var item = GetEntity(elem);
                list.Add(item);
            }
            return list;
        }

        public T Get(string id)
        {
            var root = _xmlHelper.Load(_path);
            var element = root.Elements(_elementName)
                .SingleOrDefault(elem => (string)elem.Attribute(_idName) == id);
            var item = element == null ? default(T) : GetEntity(element);
            return item;
        }

        public bool Create(T item)
        {
            var root = _xmlHelper.Load(_path);
            string id = GetId(item);
            var element =   root.Elements(_elementName)
                                .SingleOrDefault(elem => (string)elem.Attribute(_idName) == id);

            bool result = element == null;
            if (element == null)
            {
                element = GetElement(item);
                root.Add(element);
                _xmlHelper.Save(root, _path);
            }
            return result;
        }

        public bool Update(string olid, T item)
        {
            var root = _xmlHelper.Load(_path);
            var element = root.Elements(_elementName).SingleOrDefault(elem => (string)elem.Attribute(_idName) == olid);
            if (element != null)
            {
                UpdateElement(element, item);
                _xmlHelper.Save(root, _path);
            }
            return element != null;
        }

        public bool Delete(string id)
        {
            var root = _xmlHelper.Load(_path);
            var delElem = root.Elements(_elementName)
                              .SingleOrDefault(elem => 
                                  elem.Attribute(_idName)
                                      .Value
                                      .Equals(id));

            if (delElem != null)
            {
                delElem.Remove();
                _xmlHelper.Save(root, _path);
            }
            return delElem != null;
        }

        public IXmlHelper XmlHelper
        {
            get
            {
                return _xmlHelper;
            }
        }
        
        public IDataContext DataContext
        {
            get
            {
                return _context;
            }
        }

        public string Path
        {
            get
            {
                return _path;
            }
        }

        protected string _path;
        protected string _elementName;
        protected string _idName = "ID";

        protected abstract T GetEntity(XElement elem);
        protected abstract XElement GetElement(T item);
        protected abstract void UpdateElement(XElement elem, T item);
        protected abstract string GetId(T item);
        protected abstract void SetId(T item, string id);

        private IDataContext _context;
        private IXmlHelper _xmlHelper;
    }
}
